package com.ljh.mall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ljh.common.constant.OrderConstant;
import com.ljh.common.dto.SeckillOrderDto;
import com.ljh.common.exception.NoStockExecption;
import com.ljh.common.utils.R;
import com.ljh.common.vo.MemberVO;
import com.ljh.mall.order.dto.OrderCreateDTO;
import com.ljh.mall.order.entity.OrderItemEntity;
import com.ljh.mall.order.feign.WareFeignService;
import com.ljh.mall.order.interceptor.AuthInterceptor;
import com.ljh.mall.order.feign.CartFeginService;
import com.ljh.mall.order.feign.MemberFeginService;
import com.ljh.mall.order.feign.ProductService;
import com.ljh.mall.order.service.OrderItemService;
import com.ljh.mall.order.vo.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljh.common.utils.PageUtils;
import com.ljh.common.utils.Query;

import com.ljh.mall.order.dao.OrderDao;
import com.ljh.mall.order.entity.OrderEntity;
import com.ljh.mall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    MemberFeginService memberFeginService;

    @Autowired
    CartFeginService cartFeginService;

    @Autowired
    ProductService productService;

    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    OrderService orderService;
    @Autowired
    OrderItemService orderItemService;

    @Autowired
    WareFeignService wareFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

//    @Override
//    public OrderConfirmVo confirmOrder() {
//        OrderConfirmVo vo = new OrderConfirmVo();
//        MemberVO memberVO = (MemberVO) AuthInterceptor.threadLocal.get();
//        // 查到当前登录的用户对于会员信息
//        Long id = memberVO.getId();
//        List<MemberAddressVo> address = memberFeginService.getAddress(id);
//        vo.setAddress(address);
//        // 查询购买车中选中的信息
//        List<OrderItemVo> userCartItems = cartFeginService.getUserCartItems();
//        vo.setItems(userCartItems);
//        return vo;
//    }
    @Override
    public OrderConfirmVo confirmOrder(){
        OrderConfirmVo vo = new OrderConfirmVo();
        MemberVO memberVO = (MemberVO)AuthInterceptor.threadLocal.get();
        //从主线程中获取   RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            // RequestContextHolder 绑定主线程中的 RequestAttributes
            // 解决异步任务拿不到ThreadLocal里的数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            Long id = memberVO.getId();
            List<MemberAddressVo> address = memberFeginService.getAddress(id);
            vo.setAddress(address);
            System.out.println("返回address"+ JSON.toJSONString(address));
        }, executor);

        CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            // 2.查询购物车中选中的商品信息
            List<OrderItemVo> userCartItems = cartFeginService.getUserCartItems();
            vo.setItems(userCartItems);
        }, executor);
        // 主线程需要等待所有的子线程完成后继续
        try {
            CompletableFuture.allOf(voidCompletableFuture,voidCompletableFuture1).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // 4.生成防重的Token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 我们需要把这个Token信息存储在Redis中
        // order:token:用户编号
        redisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX+":"+memberVO.getId(),token);
        vo.setOrderToken(token);
        System.out.println("返回数据"+ JSON.toJSONString(vo));
        return vo;
    }

    private Lock lock = new ReentrantLock();

    /*
    * 判断lua脚本的 key KEYS[1，和 value ARGV[1]，如果key 等于value ，马上删除，如果key不等于value，
    * 说明没匹配（此key 和此 value 不是一对）上或者value不存在，返回 0 end，判断返回值 eval 是否为 0 即可
    * */

    //@GlobalTransactional
    @Transactional()
    @Override
    public OrderResponseVO submitOrder(OrderSubmitVO vo) {
        //需要返回响应的对象
        OrderResponseVO responseVO = new OrderResponseVO();
        MemberVO memberVO = (MemberVO)AuthInterceptor.threadLocal.get();
        String key =OrderConstant.ORDER_TOKEN_PREFIX+":"+ memberVO.getId();
//        try{
//            lock.lock();
//            String redisToken = redisTemplate.opsForValue().get(key);
//            if (redisToken != null && redisToken.equals(vo.getOrderToken())){
//                //表示是第一次提交
//                redisTemplate.delete(key);
//            } else{
//                // 表示是重复提交
//                return responseVO;
//            }
//            // 创建订单编号
//            String orderSn = IdWorker.getTimeId();
//        } finally {
//            lock.unlock();
//        }

        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class)
                , Arrays.asList(key)
                , vo.getOrderToken());
        if (execute == 0){
            responseVO.setCode(1);
            return responseVO;
        }
        // 2.创建订单和订单项信息
        OrderCreateDTO orderCreateDTO =createOrder(vo);
        responseVO.setOrderEntity(orderCreateDTO.getOrderEntity());

        // 3.保存订单信息
        saveOrder(orderCreateDTO);

        // 4.锁定库存信息
        lockWareSkuStock(responseVO, orderCreateDTO);
        int i = 1 / 0;
        return responseVO;
    }

    /**
     * 快速完成订单的处理  秒杀活动
     * @param orderDto
     */
    @Transactional
    @Override
    public void quickCreateOrder(SeckillOrderDto orderDto) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setStatus(OrderConstant.OrderStateEnum.FOR_THE_PAYMENT.getCode());
        orderEntity.setMemberId(orderDto.getMemberId());
        orderEntity.setTotalAmount(orderDto.getSeckillPrice().multiply(new BigDecimal(orderDto.getNum())));
        save(orderEntity);
        OrderItemEntity itemEntity = new OrderItemEntity();
        // TODO 根据SKUID查询对应的SKU信息和SPU信息
        itemEntity.setOrderSn(orderDto.getOrderSN());
        itemEntity.setSkuPrice(orderDto.getSeckillPrice());
        itemEntity.setSkuId(orderDto.getSkuId());
        itemEntity.setRealAmount(orderDto.getSeckillPrice().multiply(new BigDecimal(orderDto.getNum())));
        itemEntity.setSkuQuantity(orderDto.getNum());

        orderItemService.save(itemEntity);
        System.out.println("商品秒杀订单保存成功");
    }

    private void lockWareSkuStock(OrderResponseVO responseVO,OrderCreateDTO orderCreateDTO){
        WareSkuLockVO wareSkuLockVO = new WareSkuLockVO();
        //订单号
        wareSkuLockVO.setOrderSN(orderCreateDTO.getOrderEntity().getOrderSn());
        List<OrderItemVo> collect = orderCreateDTO.getOrderItemEntitys().stream().map(item -> {
            OrderItemVo itemVo = new OrderItemVo();
            itemVo.setSkuId(item.getSkuId());
            itemVo.setTitle(item.getSkuName());
            itemVo.setCount(item.getSkuQuantity());
            return itemVo;
        }).collect(Collectors.toList());
        wareSkuLockVO.setItems(collect);
        // 远程锁库存的操作
        R r = wareFeignService.orderLockStock(wareSkuLockVO);
        if(r.getCode() == 0){
            // 表示锁定库存成功
            responseVO.setCode(0); // 表示 创建订单成功
        }else{
            // 表示锁定库存失败
            responseVO.setCode(2); // 表示库存不足，锁定失败
            throw new NoStockExecption(10000l);
        }
    }

    /**
     * 生成订单数据
     * 保存
     * @param orderCreateDTO
     */
    private void saveOrder(OrderCreateDTO orderCreateDTO){
        // 1.订单数据
        OrderEntity orderEntity = orderCreateDTO.getOrderEntity();
        orderService.save(orderEntity);
        System.out.println("---------------------------------");
        //2,订单项数据
        List<OrderItemEntity> orderItemEntitys = orderCreateDTO.getOrderItemEntitys();
        orderItemService.saveBatch(orderItemEntitys);

    }

    /**
     * 创建订单的方法
     * @param vo
     * @return
     */
    private OrderCreateDTO createOrder(OrderSubmitVO vo){
        OrderCreateDTO createDTO = new OrderCreateDTO();
        //创建订单
        OrderEntity orderEntity = buildOrder(vo);
        createDTO.setOrderEntity(orderEntity);

        // 创建OrderItemEntity 订单项
        List<OrderItemEntity> orderItemEntities = buildOrderItems(orderEntity.getOrderSn());
        // 根据订单项计算出支付总额
        BigDecimal totalAmount = new BigDecimal(0);
        for (OrderItemEntity orderItemEntity : orderItemEntities){
            BigDecimal total = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity()));

            totalAmount = totalAmount.add(total);
        }
        orderEntity.setTotalAmount(totalAmount);
        createDTO.setOrderItemEntitys(orderItemEntities);
        return createDTO;
    }

    /**
     * 通过购物车中选中的商品来创建对应的购物项信息
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String orderSN){
        List<OrderItemEntity> orderItemEntitys = new ArrayList<>();

        // 获取购物车中的商品信息 选中的
        List<OrderItemVo> userCartItems = cartFeginService.getUserCartItems();
        if(userCartItems != null && userCartItems.size() > 0){
            // 统一根据SKUID查询出对应的SPU的信息
            List<Long> spuIds = new ArrayList<>();
            for (OrderItemVo orderItemVo : userCartItems){
                if(!spuIds.contains(orderItemVo.getSpuId())){
                    spuIds.add(orderItemVo.getSpuId());
                }
            }
            Long[] spuIdsArray = new Long[spuIds.size()];
            spuIdsArray = spuIds.toArray(spuIdsArray);
            System.out.println("---->" + spuIdsArray.length);
            // 远程调用商品服务获取到对应的SPU信息

            List<OrderItemSpuInfoVO> spuInfos = productService.getOrderItemSpuInfoBySpuId(spuIdsArray);
            Map<Long, OrderItemSpuInfoVO> collect = spuInfos.stream()
                    .collect(Collectors.toMap(OrderItemSpuInfoVO::getId, it -> it));
            for (OrderItemVo userCartItem:userCartItems){
                // 获取到商品信息对应的 SPU信息
                OrderItemSpuInfoVO spuInfo = collect.get(userCartItem.getSpuId());
                // spu + sku
                OrderItemEntity orderItemEntity =buildOrderItem(userCartItem,spuInfo);
                // 绑定对应的订单编号
                orderItemEntity.setOrderSn(orderSN);
                orderItemEntitys.add(orderItemEntity);
            }

        }
        return orderItemEntitys;
    }
    /**
     * 根据一个购物车中的商品创建对应的 订单项
     * @param userCartItem
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderItemVo userCartItem,OrderItemSpuInfoVO spuInfo) {
        OrderItemEntity entity = new OrderItemEntity();
        //SKU信息
        entity.setSkuId(userCartItem.getSkuId());
        entity.setSkuName(userCartItem.getTitle());
        entity.setSkuPic(userCartItem.getImage());
        entity.setSkuQuantity(userCartItem.getCount());
        List<String> skuAttr = userCartItem.getSkuAttr();
        String skuAttrStr = StringUtils.collectionToDelimitedString(skuAttr, ";");
        System.out.println("collectionToDelimitedString"+skuAttrStr);
        entity.setSkuAttrsVals(skuAttrStr);

        // SPU信息
        entity.setSpuId(spuInfo.getId());
        entity.setSpuBrand(spuInfo.getBrandName());
        entity.setCategoryId(spuInfo.getCatalogId());
        entity.setSpuPic(spuInfo.getImg());

        entity.setGiftGrowth(userCartItem.getPrice().intValue());
        entity.setGiftIntegration(userCartItem.getPrice().intValue());
        entity.setSkuPrice(userCartItem.getPrice());
        return entity;
    }

    /**
     * 根据会员信息创建 基本订单
     * @param vo
     * @return
     */
    private OrderEntity buildOrder(OrderSubmitVO vo){
        //创建OrderEntity
        OrderEntity orderEntity = new OrderEntity();
        //Time +id
        String timeId = IdWorker.getTimeId();
        // 创建订单编号
        orderEntity.setOrderSn(timeId);
        System.out.println("订单号"+timeId);
        MemberVO memberVO = (MemberVO) AuthInterceptor.threadLocal.get();
        //设置会员相关的信息
        orderEntity.setMemberId(memberVO.getId());
        orderEntity.setMemberUsername(memberVO.getUsername());
        // 根据收获地址ID获取收获地址的详细信息
        MemberAddressVo memberAddressVo = memberFeginService.getAddressById(vo.getAddrId());
        orderEntity.setReceiverCity(memberAddressVo.getCity());
        orderEntity.setReceiverDetailAddress(memberAddressVo.getDetailAddress());
        orderEntity.setReceiverName(memberAddressVo.getName());
        orderEntity.setReceiverPhone(memberAddressVo.getPhone());
        orderEntity.setReceiverPostCode(memberAddressVo.getPostCode());
        orderEntity.setReceiverRegion(memberAddressVo.getRegion());
        orderEntity.setReceiverProvince(memberAddressVo.getProvince());
        // 订单总额
        // 设置订单的状态

        orderEntity.setStatus(OrderConstant.OrderStateEnum.FOR_THE_PAYMENT.getCode());// 待付款
        return orderEntity;
    }
}